gganimate

  • 애니메이션의 목적
    • 시간의 변화를 표현
    • 이산 변수의 값의 변화를 표현
  • ggplot 객체를 이용하여 애니메이션 객체 제작
    • 최근에 CRAN에 등장했고, 발전 가능성이 높은 패키지
    • 공식 페이지 https://gganimate.com/
    • anim_save()gif 파일 제작 가능 (ggsave()와 유사)

  • Part I. transition_time()
  • Part II. transition_states()
  • Part III. transition_reveal()

Part I. transition_time()

gapminder 데이터셋

library(gapminder)
datatable(gapminder)

A sensible figure for a single time

fig1 <-
  gapminder %>% filter(year==2007) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = country)) +
  geom_point(show.legend = FALSE, alpha = 0.7) +
  scale_color_viridis_d() + scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy")
fig1

Step 1. facet_wrap()으로 애니메이션 구상

  • faceting 으로 모든 시간에 대한 데이터를 포함할 수 있음
fig2 <-
  gapminder %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = country)) +
  geom_point(show.legend = FALSE, alpha = 0.7) +
  scale_color_viridis_d() + scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy") + 
  facet_wrap(~ year)
  • (아래는 바로 전 페이지의 코드)
fig1 <-
  gapminder %>% filter(year==2007) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = country)) +
  geom_point(show.legend = FALSE, alpha = 0.7) +
  scale_color_viridis_d() + scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy")

fig2

  • 애니메이션은 위의 facet들을 interpolate하여 한 화면에 보여주는 것

Step 2. An insensible static figure

  • 앞의 fig2에서 facet_wrap(~ year)을 빼서 insensible한 static ggplot 객체를 생성
fig_static <-
  gapminder %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = country)) +
  geom_point(show.legend = FALSE, alpha = 0.7) +
  scale_color_viridis_d() + scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy")
  • (아래는 바로 전 페이지의 코드)
fig2 <-
  gapminder %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = country)) +
  geom_point(show.legend = FALSE, alpha = 0.7) +
  scale_color_viridis_d() + scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy") + 
  facet_wrap(~ year)

fig_static

  • fig_static은 그야말로 insensible 하지만…

Step 3. 애니메이션 완성

fig_dynamic <- fig_static + 
  transition_time(year) +
  labs(title = "Year: {frame_time}")
class(fig_dynamic)
## [1] "gganim" "gg"     "ggplot"
  • facet_wrap() 대신에 transition_time()을 사용한다고 이해하면 쉬움
anim_save(filename = "anim_gapminder.gif", 
          animation = fig_dynamic,
          renderer = gifski_renderer())
  • 708kb 크기의 gif 파일이 저장됨
  • 화질 개선 등의 부분에서 빠른 발전이 예상되는 패키지

include_graphics("anim_gapminder.gif")

한개 더 만들어 봅시다.

library(tidytext)
# Filter G7 countries
G7 <- gapminder %>%  
  filter(
    country %in% c("Canada", "France", "Germany", "Italy", 
                   "Japan", "United Kingdom", "United States"))
  • Step 1. facet_wrap()으로 애니메이션 구상
fig_facet <- 
  G7 %>% 
  ggplot(aes(x = reorder(country, gdpPercap), y = gdpPercap, fill = country)) +
  geom_col() + 
  coord_flip() + 
  labs(x = NULL, y = "GDP per capita") + 
  theme(legend.position = "none") + 
  facet_wrap(~ year)

fig_facet

  • Step 2. fig_static 만들기
fig_static <- 
  G7 %>% 
  ggplot(aes(x = reorder(country, gdpPercap), y = gdpPercap, fill = country)) +
  geom_col() + 
  coord_flip() + 
  labs(x = NULL, y = "GDP per capita") +
  theme(legend.position = "none")
  • Step 3. fig_dynamic 만들고 저장
fig_dynamic <- 
  fig_static + transition_time(year) + labs(title = "Year: {frame_time}")

anim_save(filename = "anim_gdp.gif", 
          animation = fig_dynamic,
          renderer = gifski_renderer())

include_graphics("anim_gdp.gif")

Part II. transition_states()

transition_states()

  • 이산 변수의 값의 차이에 따라서 데이터가 어떻게 변화하는 지를 표현
  • facet_wrap()의 각 facet들이 번갈아가면서 보여짐

Approach

  • transition_time()과 비슷하게 아래의 3단계 접근을 사용
    • Step 1. facet_wrap()으로 애니메이션 구상
    • Step 2. fig_static 만들기
    • Step 3. fig_dynamic 만들고 저장

Step 1. facet_wrap()으로 애니메이션 구상

fig1 <-
  gapminder %>% filter(year==2007) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = continent)) +
  geom_point(show.legend = FALSE) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy") +
  facet_wrap(~ continent)

fig1

  • 위의 순서대로 애니메이션이 생성되는 것 보다 평균수명 순서대로 표현되게 하기 위하여 아래 코드 추가
gapminder$continent <- factor(gapminder$continent, 
                              levels = c("Africa", "Asia", "Americas", "Europe", "Oceania"))
  • 그리고, 다시 만들기
fig1 <-
  gapminder %>% filter(year==2007) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = continent)) +
  geom_point(show.legend = FALSE) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy") +
  facet_wrap(~ continent)

fig1

Step 2. fig_static 만들기

fig_static <-
  gapminder %>% filter(year==2007) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = continent)) +
  geom_point(show.legend = FALSE) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy")

Step 3. fig_dynamic 만들고 저장

fig_dynamic <- 
  fig_static + transition_states(continent) + labs(title = "Now Showing {closest_state}")

anim_save(filename = "anim_continent.gif", 
          animation = fig_dynamic,
          renderer = gifski_renderer())
  • The following is the previous code for transition_time()
fig_dynamic <- 
  fig_static + transition_time(year) + labs(title = "Year: {frame_time}")

include_graphics("anim_continent.gif")

Takeaway: facet_wrap()만 보면 animation을 생각해 보세요. 노력에 비해서 훨씬 있어보임.

한 개 더!

Step 2. fig_static 만들기

fig_static <- 
  gapminder %>% filter(year %in% c(1957, 1982, 2007)) %>% 
  ggplot(aes(x = gdpPercap, y=lifeExp, size = pop, colour = continent)) +
  geom_point(show.legend = FALSE) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() + labs(x = "GDP per capita", y = "Life expectancy") +
  facet_wrap(~ year)

fig_static

Step 3. fig_dynamic 만들고 저장

fig_dynamic <- 
  fig_static + transition_states(continent) + labs(title = "Now Showing {closest_state}")

anim_save(filename = "anim_continent2.gif", 
          animation = fig_dynamic,
          renderer = gifski_renderer(),
          height = 350, width = 1200)
include_graphics("anim_continent2.gif")

Part III. transition_reveal()

transition_reveal()

  • 그래프의 모습을 단계적으로 공개하는 방식으로 애니메이션 제작
  • 주로 X축에 해당하는 변수를 사용하는 것으로 생각할 수 있음
  • (지금은 이것 밖에 안 떠오르는데 아이디어 있으면 공유 부탁드립니다)

Step 1. fig_static 만들기

fig_static <- gapminder %>% 
  group_by(year, continent) %>% 
  summarise(lifeExp = mean(lifeExp)) %>%
  ggplot(aes(x=year, y=lifeExp, group = continent, color = continent)) + geom_path()
fig_static

Step 2. fig_dynamic 만들어서 저장

fig_dynamic <- fig_static + transition_reveal(year) + geom_point()
anim_save(filename = "anim_year.gif", animation = fig_dynamic,
          renderer = gifski_renderer(), height = 300, width = 500)
include_graphics("anim_year.gif")

한개더!

Step 1. fig_static 만들기

gapminder$continent <- factor(gapminder$continent, 
                              levels = c("Africa", "Americas", "Asia", "Europe", "Oceania"))
fig_static <- gapminder %>% 
  group_by(year, continent) %>% 
  summarise(gdpPercap = mean(gdpPercap)) %>% 
  ggplot(aes(x = factor(year), y = gdpPercap)) + 
  geom_col(aes(fill = continent), position = "dodge") + 
  theme(axis.title.x=element_blank())
fig_static

Step 2. fig_dynamic 만들기

fig_dynamic <- fig_static + transition_reveal(year)
anim_save(filename = "anim_year2.gif", animation = fig_dynamic,
          renderer = gifski_renderer(), height = 300, width = 500)
include_graphics("anim_year2.gif")

The happiest people have a sense of commitment in everything they do. – Dr. Bob Rotella